/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo } from 'react';
import { AdaptiveBottomSheetProps, AnimateToPositionType } from './types';
import { AdaptiveSheetMethods } from '../../types';
import AdaptiveSheetGestureHandlersProvider from '../adaptiveSheetGestureHandlersProvider';
import AdaptiveSheetBackdropContainer from '../adaptiveSheetBackdropContainer';
import Animated, {
  cancelAnimation,
  Extrapolation,
  interpolate,
  ReduceMotion,
  runOnJS,
  runOnUI,
  SharedValue,
  useAnimatedReaction,
  useAnimatedStyle,
  useDerivedValue,
  useSharedValue,
  useWorkletCallback,
  WithSpringConfig,
  WithTimingConfig,
} from 'react-native-reanimated';
import {
  DEFAULT_ANIMATE_ON_MOUNT,
  DEFAULT_DYNAMIC_SIZING,
  DEFAULT_ENABLE_CONTENT_PANNING_GESTURE,
  DEFAULT_ENABLE_HANDLE_PANNING_GESTURE,
  DEFAULT_ENABLE_OVER_DRAG,
  DEFAULT_ENABLE_PAN_DOWN_TO_CLOSE,
  DEFAULT_ENABLE_DRAG_TO_CLOSE,
  DEFAULT_HEADER_MODE,
  DEFAULT_HEADER_HEIGHT,
  DEFAULT_HEADER_CLOSE_BUTTON_COLOR,
  DEFAULT_OVER_DRAG_RESISTANCE_FACTOR,
  INITIAL_CONTAINER_HEIGHT,
  INITIAL_CONTAINER_OFFSET,
  INITIAL_HANDLE_HEIGHT,
  INITIAL_POSITION,
  INITIAL_SNAP_POINT,
  INITIAL_VALUE,
} from './constants';
import AdaptiveSheetContainer from '../adaptiveSheetContainer';
import { useNormalizedSnapPoints, usePropsValidator, useReactiveSharedValue, useScrollable } from '../../hooks';
import { Insets, Platform } from 'react-native';
import AdaptiveSheetBackgroundContainer from '../adaptiveSheetBackgroundContainer';
import { styles } from './styles';
import { AdaptiveSheetInternalProvider, AdaptiveSheetProvider } from '../../contexts';
import { ANIMATION_SOURCE, ANIMATION_STATE, SCROLLABLE_STATE, SHEET_STATE, WINDOW_WIDTH } from '../../constants';
import { State } from 'react-native-gesture-handler';
import { animate, normalizeSnapPoint, print } from '../../utilities';
import invariant from 'invariant';
import AdaptiveSheetHandleContainer from '../adaptiveSheetHandleContainer';
import AdaptiveSheetDraggableView from '../adaptiveSheetDraggableView';
import AdaptiveSheetFooterContainer from '../adaptiveSheetFooterContainer/AdaptiveSheetFooterContainer';
import AdaptiveSheetFixedHeader from './AdaptiveSheetFixedHeader';

// 组件定义
type AdaptiveBottomSheet = AdaptiveSheetMethods;

const AdaptiveBottomSheetComponent = forwardRef<AdaptiveBottomSheet, AdaptiveBottomSheetProps>(function AdaptiveBottomSheet(props, _ref) {
  usePropsValidator(props);

  const {
    // 动画
    animationConfigs, 
    index: _providedIndex = 0, 
    snapPoints: _providedSnapPoints, 
    animateOnMount = DEFAULT_ANIMATE_ON_MOUNT,
    enableContentPanningGesture = DEFAULT_ENABLE_CONTENT_PANNING_GESTURE, 
    enableHandlePanningGesture = DEFAULT_ENABLE_HANDLE_PANNING_GESTURE, 
    enableOverDrag = DEFAULT_ENABLE_OVER_DRAG, 
    enablePanDownToClose = DEFAULT_ENABLE_PAN_DOWN_TO_CLOSE,
    enableDragToClose = DEFAULT_ENABLE_DRAG_TO_CLOSE,
    enableDynamicSizing = DEFAULT_DYNAMIC_SIZING, 
    overDragResistanceFactor = DEFAULT_OVER_DRAG_RESISTANCE_FACTOR, 

    // styles
    style: _providedStyle, 
    containerStyle: _providedContainerStyle, 
    backgroundStyle: _providedBackgroundStyle, 
    handleStyle: _providedHandleStyle,
    handleIndicatorStyle: _providedHandleIndicatorStyle, 

    // hooks
    gestureEventsHandlersHook, 

    // layout
    handleHeight: _providedHandleHeight, 
    containerHeight: _providedContainerHeight, 
    contentHeight: _providedContentHeight,
    containerOffset: _providedContainerOffset,
    topInset = 0,
    bottomInset = 0,
    maxDynamicContentSize,

    // animated callback shared values
    animatedPosition: _providedAnimatedPosition, 
    animatedIndex: _providedAnimatedIndex,

    // gestures
    simultaneousHandlers: _providedSimultaneousHandlers, 
    waitFor: _providedWaitFor, 
    activeOffsetX: _providedActiveOffsetX, 
    activeOffsetY: _providedActiveOffsetY, 
    failOffsetX: _providedFailOffsetX,
    failOffsetY: _providedFailOffsetY,

    // callbacks
    onStateChange: _providedOnStateChange, // 状态变化回调
    onSizeChange: _providedOnPositionChange, // 位置变化回调
    onAnimate: _providedOnAnimate, 

    // private
    $modal = false, 
    detached = false, 

    // header (fixed mode)
    headerMode = DEFAULT_HEADER_MODE,
    headerComponent: CustomHeaderComponent,
    headerHeight = DEFAULT_HEADER_HEIGHT,
    headerTitle,
    headerLeftButton,
    headerRightButton,
    onHeaderLeftPress,
    onHeaderRightPress,
    headerTitleStyle,
    headerContainerStyle,
    headerCloseButtonColor,

    // components
    handleComponent, 
    backdropComponent, 
    backgroundComponent, 
    footerComponent, 
    children: Content, 
  } = props;

  const _providedAnimationConfigs = useMemo(() => {
    if (!animationConfigs) {
      return undefined; 
    }

    if (ReduceMotion) {
      animationConfigs.reduceMotion = ReduceMotion.Never; 
    }

    return animationConfigs;
  }, [animationConfigs]);

  // 布局变量
  const _animatedContainerHeight = useReactiveSharedValue(
    _providedContainerHeight ?? INITIAL_CONTAINER_HEIGHT, 
  );
  const animatedContainerHeight = useDerivedValue(() => {
    return _animatedContainerHeight.value;
  }, []);
  const animatedContainerOffset = useReactiveSharedValue(_providedContainerOffset ?? INITIAL_CONTAINER_OFFSET) as SharedValue<Insets>;
  const effectiveHandleHeight = headerMode === 'fixed' ? headerHeight : _providedHandleHeight;
  const animatedHandleHeight = useReactiveSharedValue(effectiveHandleHeight ?? INITIAL_HANDLE_HEIGHT);
  const animatedFooterHeight = useSharedValue(0);
  const animatedContentHeight = useSharedValue(INITIAL_CONTAINER_HEIGHT);
  const animatedSnapPoints = useNormalizedSnapPoints(
    _providedSnapPoints,
    animatedContainerHeight,
    animatedContentHeight,
    animatedHandleHeight,
    enableDynamicSizing,
    maxDynamicContentSize,
  );

  const isNewSnapPointMode = useDerivedValue(() => {
    const snapPointsArray = animatedSnapPoints.value;
    if (snapPointsArray.length === 4) {
      const lastElement = snapPointsArray[3];
      return lastElement === 0 || lastElement === 1;
    }
    return false;
  });

  const animatedHighestSnapPoint = useDerivedValue(() => {
    if (isNewSnapPointMode.value) {
      return animatedSnapPoints.value[2];
    }
    return animatedSnapPoints.value[animatedSnapPoints.value.length - 1];
  });
  const animatedClosedPosition = useDerivedValue(() => {
    return animatedContainerHeight.value;
  }, []);
  const animatedSheetHeight = useDerivedValue(() => animatedContainerHeight.value - animatedHighestSnapPoint.value);
  const animatedCurrentIndex = useReactiveSharedValue(animateOnMount ? -1 : _providedIndex);
  const animatedPosition = useSharedValue(INITIAL_POSITION);
  const animatedNextPosition = useSharedValue(INITIAL_VALUE);
  const animatedNextPositionIndex = useSharedValue(0);

  // 条件
  const isAnimatedOnMount = useSharedValue(false);
  const isContentHeightFixed = useSharedValue(false);
  const isLayoutCalculated = useDerivedValue(() => {
    let isContainerHeightCalculated = false;
    if (_providedContainerHeight !== null || _providedContainerHeight !== undefined) {
      isContainerHeightCalculated = true; 
    }
    if (animatedContainerHeight.value !== INITIAL_CONTAINER_HEIGHT) {
      isContainerHeightCalculated = true; 
    }

    let isHandleHeightCalculated = false;
    if (_providedHandleHeight !== null && _providedHandleHeight !== undefined && typeof _providedHandleHeight === 'number') {
      isHandleHeightCalculated = true;
    }
    if (handleComponent === null) {
      animatedHandleHeight.value = 0;
      isHandleHeightCalculated = true;
    }
    if (animatedHandleHeight.value !== INITIAL_HANDLE_HEIGHT) {
      isHandleHeightCalculated = true;
    }

    let isSnapPointsNormalized = false;
    if (animatedSnapPoints.value[0] !== INITIAL_SNAP_POINT) {
      isSnapPointsNormalized = true;
    }

    return isContainerHeightCalculated && isHandleHeightCalculated && isSnapPointsNormalized;
  });
  const isInTemporaryPosition = useSharedValue(false);
  const isForcedClosing = useSharedValue(false);

  // gesture
  const animatedContentGestureState = useSharedValue<State>(State.UNDETERMINED);
  const animatedHandleGestureState = useSharedValue<State>(State.UNDETERMINED);

  // hooks
  const {
    animatedScrollableType, 
    animatedScrollableContentOffsetY,
    animatedScrollableOverrideState, 
    isScrollableRefreshable, 
    setScrollableRef, 
    removeScrollableRef, 
  } = useScrollable();

  // states
  const animatedAnimationState = useSharedValue(ANIMATION_STATE.UNDETERMINED);
  const animatedAnimationSource = useSharedValue<ANIMATION_SOURCE>(ANIMATION_SOURCE.MOUNT);
  const animatedSheetState = useDerivedValue(() => {
    if (animatedPosition.value >= animatedClosedPosition.value) {
      return SHEET_STATE.CLOSED;
    } 

    const extendedPosition = animatedContainerHeight.value - animatedSheetHeight.value;
    if (animatedPosition.value === extendedPosition) {
      return SHEET_STATE.EXTENDED;
    } 

    if (animatedPosition.value === 0) {
      return SHEET_STATE.FILL_PARENT; 
    }

    // detect if position is below extended point
    if (animatedPosition.value < extendedPosition) {
      return SHEET_STATE.OVER_EXTENDED;
    }

    return SHEET_STATE.OPENED; 
  }, [animatedClosedPosition, animatedContainerHeight, animatedPosition, animatedSheetHeight, isInTemporaryPosition]);
  const animatedScrollableState = useDerivedValue(() => {
    if (animatedScrollableOverrideState.value !== SCROLLABLE_STATE.UNDETERMINED) {
      return animatedScrollableOverrideState.value;
    }
    if (animatedSheetState.value === SHEET_STATE.FILL_PARENT) {
      return SCROLLABLE_STATE.UNLOCKED;
    }
    if (animatedSheetState.value === SHEET_STATE.EXTENDED) {
      return SCROLLABLE_STATE.UNLOCKED;
    }

    return SCROLLABLE_STATE.LOCKED;
  });
  // dynamic
  const animatedContentHeightMax = useDerivedValue(() => {
    const handleHeight = Math.max(0, animatedHandleHeight.value);
    const contentHeight = animatedSheetHeight.value - handleHeight;
    return Math.max(contentHeight, 0);
  }, [animatedHandleHeight, animatedSheetHeight]);
  const animatedIndex = useDerivedValue(() => {
    const snapPoints = animatedSnapPoints.value;
    const isNewMode = snapPoints.length === 4 && (snapPoints[3] === 0 || snapPoints[3] === 1);

    let adjustedSnapPoints: number[];
    let adjustedSnapPointsIndexes: number[];

    if (isNewMode) {
      const defaultPos = snapPoints[0];
      const minPos = snapPoints[1];
      const maxPos = snapPoints[2];

      adjustedSnapPoints = [maxPos, defaultPos, minPos];
      adjustedSnapPointsIndexes = [2, 0, 1]; 
    } else {
      adjustedSnapPoints = snapPoints.slice().reverse();
      adjustedSnapPointsIndexes = snapPoints
        .slice()
        .map((_: string | number, index: number) => index)
        .reverse();
    }

    adjustedSnapPoints.push(animatedContainerHeight.value);
    adjustedSnapPointsIndexes.push(-1);

    const currentIndex = isLayoutCalculated.value
      ? interpolate(animatedPosition.value, adjustedSnapPoints, adjustedSnapPointsIndexes, Extrapolation.CLAMP)
      : -1;

    if (animatedAnimationSource.value === ANIMATION_SOURCE.SNAP_POINT_CHANGE && animatedAnimationState.value === ANIMATION_STATE.RUNNING) {
      return animatedNextPositionIndex.value;
    }

    return currentIndex;
  }, []);

  // 获取下一个位置
  const getNextPosition = useWorkletCallback(
    function getNextPosition() {
      'worklet';
      const currentIndex = animatedCurrentIndex.value;
      const snapPoints = animatedSnapPoints.value;

      if (isInTemporaryPosition.value) {
        return animatedPosition.value;
      }

      return snapPoints[currentIndex];
    },
    [animatedCurrentIndex, animatedPosition, animatedSnapPoints, isInTemporaryPosition],
  );
  const handleOnStateChange = useCallback(
    function handleOnStateChange(index: number) {
      print({
        component: AdaptiveBottomSheet.name,
        method: handleOnStateChange.name,
        params: {
          index,
          animatedCurrentIndex: animatedCurrentIndex.value,
        },
      });

      if (_providedOnStateChange) {
        _providedOnStateChange(index);
      }
    },
    [_providedOnStateChange, animatedCurrentIndex],
  );
  const handleOnAnimate = useCallback(
    function handleOnAnimate(toPoint: number) {
      const snapPoints = animatedSnapPoints.value;
      const toIndex = snapPoints.indexOf(toPoint);

      print({
        component: AdaptiveBottomSheet.name,
        method: handleOnAnimate.name,
        params: {
          toIndex,
          fromIndex: animatedCurrentIndex.value,
        },
      });

      if (!_providedOnAnimate) {
        return;
      }

      if (toIndex !== animatedCurrentIndex.value) {
        _providedOnAnimate(animatedCurrentIndex.value, toIndex);
      }
    },
    [_providedOnAnimate, animatedSnapPoints, animatedCurrentIndex],
  );

  // 动画相关配置
  const stopAnimation = useWorkletCallback(() => {
    cancelAnimation(animatedPosition);
    isForcedClosing.value = false;
    animatedAnimationSource.value = ANIMATION_SOURCE.NONE;
    animatedAnimationState.value = ANIMATION_STATE.STOPPED;
  }, [animatedPosition, animatedAnimationState, animatedAnimationSource]);
  const animateToPositionCompleted = useWorkletCallback(function animateToPositionCompleted(isFinished?: boolean) {
    isForcedClosing.value = false;

    if (!isFinished) {
      return;
    }
    runOnJS(print)({
      component: AdaptiveBottomSheet.name,
      method: animateToPositionCompleted.name,
      params: {
        animatedCurrentIndex: animatedCurrentIndex.value,
        animatedNextPosition: animatedNextPosition.value,
        animatedNextPositionIndex: animatedNextPositionIndex.value,
      },
    });

    animatedAnimationSource.value = ANIMATION_SOURCE.NONE;
    animatedAnimationState.value = ANIMATION_STATE.STOPPED;
    animatedNextPosition.value = INITIAL_VALUE;
    animatedNextPositionIndex.value = INITIAL_VALUE;
  });
  const animateToPosition: AnimateToPositionType = useWorkletCallback(
    function animateToPosition(position: number, source: ANIMATION_SOURCE, velocity = 0, configs?: WithTimingConfig | WithSpringConfig) {
      if (
        position === animatedPosition.value ||
        position === undefined ||
        (animatedAnimationState.value === ANIMATION_STATE.RUNNING && position === animatedNextPosition.value)
      ) {
        return;
      }

      runOnJS(print)({
        component: AdaptiveBottomSheet.name,
        method: animateToPosition.name,
        params: {
          currentPosition: animatedPosition.value,
          position,
          velocity,
          animatedContainerHeight: animatedContainerHeight.value,
        },
      });

      stopAnimation();

      animatedAnimationState.value = ANIMATION_STATE.RUNNING;
      animatedAnimationSource.value = source;

      animatedNextPosition.value = position;
      animatedNextPositionIndex.value = animatedSnapPoints.value.indexOf(position);

      runOnJS(handleOnAnimate)(position);

      if (configs !== undefined) {
        if (ReduceMotion) {
          configs.reduceMotion = ReduceMotion.Never;
        }
        animatedPosition.value = animate({
          point: position,
          configs,
          velocity,
          onComplete: animateToPositionCompleted,
        });
      } else {
        animatedPosition.value = animate({
          point: position,
          velocity,
          configs: _providedAnimationConfigs,
          onComplete: animateToPositionCompleted,
        });
      }
    },
    [handleOnAnimate, _providedAnimationConfigs],
  );

  // 公开方法
  const handleSnapToIndex = useCallback(
    function handleSnapToIndex(index: number, animationConfigs?: WithSpringConfig | WithTimingConfig) {
      const snapPoints = animatedSnapPoints.value;
      invariant(
        index >= -1 && index <= snapPoints.length - 1,
        `'index' was provided but out of the provided snap points range! expected value to be between -1, ${snapPoints.length - 1}`,
      );
      print({
        component: AdaptiveBottomSheet.name,
        method: handleSnapToIndex.name,
        params: {
          index,
        },
      });

      const nextPosition = snapPoints[index];

      if (!isLayoutCalculated.value || index === animatedNextPositionIndex.value || nextPosition === animatedNextPosition.value || isForcedClosing.value) {
        return;
      }

      isInTemporaryPosition.value = false;

      runOnUI(animateToPosition)(nextPosition, ANIMATION_SOURCE.USER, 0, animationConfigs);
    },
    [animateToPosition, isLayoutCalculated, isInTemporaryPosition, isForcedClosing, animatedSnapPoints, animatedNextPosition, animatedNextPositionIndex],
  );
  const handleSnapToPosition = useWorkletCallback(
    function handleSnapToPosition(position: number | string, animationConfigs?: WithSpringConfig | WithTimingConfig) {
      print({
        component: AdaptiveBottomSheet.name,
        method: handleSnapToPosition.name,
        params: {
          position,
        },
      });

      const nextPosition = normalizeSnapPoint(position, animatedContainerHeight.value);

      if (!isLayoutCalculated || nextPosition === animatedNextPosition.value || isForcedClosing.value) {
        return;
      }

      isInTemporaryPosition.value = true;

      runOnUI(animateToPosition)(nextPosition, ANIMATION_SOURCE.USER, 0, animationConfigs);
    },
    [animateToPosition, isLayoutCalculated, isForcedClosing, animatedContainerHeight, animatedPosition],
  );
  const handleClose = useCallback(
    function handleClose(animationConfigs?: WithSpringConfig | WithTimingConfig) {
      print({
        component: AdaptiveBottomSheet.name,
        method: handleClose.name,
      });

      const nextPosition = animatedClosedPosition.value;

      if (!isLayoutCalculated.value || nextPosition === animatedNextPosition.value || isForcedClosing.value) {
        return;
      }

      isInTemporaryPosition.value = false;

      runOnUI(animateToPosition)(nextPosition, ANIMATION_SOURCE.USER, 0, animationConfigs);
    },
    [animateToPosition, isForcedClosing, isLayoutCalculated, isInTemporaryPosition, animatedNextPosition, animatedClosedPosition],
  );
  const handleForceClose = useCallback(
    function handleForceClose(animationConfigs?: WithSpringConfig | WithTimingConfig) {
      print({
        component: AdaptiveBottomSheet.name,
        method: handleForceClose.name,
      });

      const nextPosition = animatedClosedPosition.value;

      if (nextPosition === animatedNextPosition.value || isForcedClosing.value) {
        return;
      }

      isInTemporaryPosition.value = false;

      isForcedClosing.value = true;

      runOnUI(animateToPosition)(nextPosition, ANIMATION_SOURCE.USER, 0, animationConfigs);
    },
    [animateToPosition, isForcedClosing, isInTemporaryPosition, animatedNextPosition, animatedClosedPosition],
  );
  const handleExpand = useCallback(
    function handleExpand(animationConfigs?: WithSpringConfig | WithTimingConfig) {
      print({
        component: AdaptiveBottomSheet.name,
        method: handleExpand.name,
      });

      const snapPoints = animatedSnapPoints.value;
      const nextPosition = snapPoints[snapPoints.length - 1];

      if (
        !isLayoutCalculated.value ||
        snapPoints.length - 1 === animatedNextPositionIndex.value ||
        nextPosition === animatedNextPosition.value ||
        isForcedClosing.value
      ) {
        return;
      }

      isInTemporaryPosition.value = false;

      runOnUI(animateToPosition)(nextPosition, ANIMATION_SOURCE.USER, 0, animationConfigs);
    },
    [animateToPosition, isInTemporaryPosition, isLayoutCalculated, isForcedClosing, animatedSnapPoints, animatedNextPosition, animatedNextPositionIndex],
  );
  const handleCollapse = useCallback(
    function handleCollapse(animationConfigs?: WithSpringConfig | WithTimingConfig) {
      print({
        component: AdaptiveBottomSheet.name,
        method: handleCollapse.name,
      });

      const nextPosition = animatedSnapPoints.value[0];

      if (!isLayoutCalculated || animatedNextPositionIndex.value === 0 || nextPosition === animatedNextPosition.value || isForcedClosing.value) {
        return;
      }

      isInTemporaryPosition.value = false;

      runOnUI(animateToPosition)(nextPosition, ANIMATION_SOURCE.USER, 0, animationConfigs);
    },
    [animateToPosition, isForcedClosing, isLayoutCalculated, isInTemporaryPosition, animatedSnapPoints, animatedNextPosition, animatedNextPositionIndex],
  );

  useImperativeHandle(_ref, () => ({
    snapToIndex: handleSnapToIndex,
    snapToPosition: handleSnapToPosition,
    expand: handleExpand,
    collapse: handleCollapse,
    close: handleClose,
    forceClose: handleForceClose,
  }));

  // 上下文
  const internalContextVariables = useMemo(
    () => ({
      enableContentPanningGesture,
      enableDynamicSizing,
      overDragResistanceFactor,
      enableOverDrag,
      enablePanDownToClose,
      animatedAnimationState,
      animatedSheetState,
      animatedScrollableState,
      animatedScrollableOverrideState,
      animatedContentGestureState,
      animatedHandleGestureState,
      animatedScrollableType,
      animatedIndex,
      animatedPosition,
      animatedContentHeight,
      animatedClosedPosition,
      animatedHandleHeight,
      animatedFooterHeight,
      animatedContainerHeight,
      animatedSnapPoints,
      animatedHighestSnapPoint,
      animatedScrollableContentOffsetY,
      isInTemporaryPosition,
      isContentHeightFixed,
      isScrollableRefreshable,
      simultaneousHandlers: _providedSimultaneousHandlers,
      waitFor: _providedWaitFor,
      activeOffsetX: _providedActiveOffsetX,
      activeOffsetY: _providedActiveOffsetY,
      failOffsetX: _providedFailOffsetX,
      failOffsetY: _providedFailOffsetY,
      animateToPosition,
      stopAnimation,
      setScrollableRef,
      removeScrollableRef,
    }),
    [
      animatedIndex,
      animatedPosition,
      animatedContentHeight,
      animatedScrollableType,
      animatedContentGestureState,
      animatedHandleGestureState,
      animatedClosedPosition,
      animatedFooterHeight,
      animatedContainerHeight,
      animatedHandleHeight,
      animatedAnimationState,
      animatedSheetState,
      animatedHighestSnapPoint,
      animatedScrollableState,
      animatedScrollableOverrideState,
      animatedSnapPoints,
      animatedScrollableContentOffsetY,
      isScrollableRefreshable,
      isContentHeightFixed,
      isInTemporaryPosition,
      enableContentPanningGesture,
      overDragResistanceFactor,
      enableOverDrag,
      enablePanDownToClose,
      enableDynamicSizing,
      _providedSimultaneousHandlers,
      _providedWaitFor,
      _providedActiveOffsetX,
      _providedActiveOffsetY,
      _providedFailOffsetX,
      _providedFailOffsetY,
      setScrollableRef,
      removeScrollableRef,
      animateToPosition,
      stopAnimation,
    ],
  );
  const externalContextVariables = useMemo(
    () => ({
      animatedIndex,
      animatedPosition,
      snapToIndex: handleSnapToIndex,
      snapToPosition: handleSnapToPosition,
      expand: handleExpand,
      collapse: handleCollapse,
      close: handleClose,
      forceClose: handleForceClose,
    }),
    [animatedIndex, animatedPosition, handleSnapToIndex, handleSnapToPosition, handleExpand, handleCollapse, handleClose, handleForceClose],
  );

  // style
  const containerAnimatedStyle = useAnimatedStyle(
    () => ({
      opacity: Platform.OS === 'android' && animatedIndex.value === -1 ? 0 : 1,
      transform: [
        {
          translateY: animatedPosition.value,
        },
      ],
    }),
    [animatedPosition, animatedIndex],
  );
  const containerStyle = useMemo(() => [_providedStyle, styles.container, containerAnimatedStyle], [_providedStyle, containerAnimatedStyle]);
  const contentContainerAnimatedStyle = useAnimatedStyle(() => {
    if (_providedContentHeight) {
      return {};
    }

    return {
      height: animate({
        point: animatedContentHeightMax.value,
        configs: _providedAnimationConfigs,
      }),
    };
  }, [animatedContentHeightMax, enableDynamicSizing, animatedContentHeight]);

  const contentContainerStyle = useMemo(() => [styles.contentContainer, contentContainerAnimatedStyle], [contentContainerAnimatedStyle]);
  const contentMaskContainerAnimatedStyle = useAnimatedStyle(() => {
    if (detached) {
      return {
        overflow: 'visible',
      };
    }

    return {
      paddingBottom: animatedContainerHeight.value,
    };
  }, [detached]);

  const contentMaskContainerStyle = useMemo(() => [styles.contentMaskContainer, contentMaskContainerAnimatedStyle], [contentMaskContainerAnimatedStyle]);
  const borderRadiusStyle = useMemo(() => {
    if (!_providedStyle) {
      return {};
    }

    const flattenedStyle = Array.isArray(_providedStyle) ? Object.assign({}, ..._providedStyle.filter(Boolean)) : _providedStyle;

    return {
      borderTopLeftRadius: flattenedStyle.borderTopLeftRadius,
      borderTopRightRadius: flattenedStyle.borderTopRightRadius,
      borderBottomLeftRadius: flattenedStyle.borderBottomLeftRadius,
      borderBottomRightRadius: flattenedStyle.borderBottomRightRadius,
      borderRadius: flattenedStyle.borderRadius,
    };
  }, [_providedStyle]);


  // effects
  useAnimatedReaction(
    () => isLayoutCalculated.value,
    _isLayoutCalculated => {
      /**
       * exit method if:
       * - layout is not calculated yet.
       * - already did animate on mount.
       */
      if (!_isLayoutCalculated || isAnimatedOnMount.value) {
        return;
      }

      let nextPosition;
      if (_providedIndex === -1) {
        nextPosition = animatedClosedPosition.value;
        animatedNextPositionIndex.value = -1;
      } else {
        nextPosition = animatedSnapPoints.value[_providedIndex];
      }

      runOnJS(print)({
        component: AdaptiveBottomSheet.name,
        method: 'useAnimatedReaction::OnMount',
        params: {
          isLayoutCalculated: _isLayoutCalculated,
          animatedSnapPoints: animatedSnapPoints.value,
          nextPosition,
        },
      });

      // 拖拽时超过边界
      if (nextPosition === INITIAL_POSITION || nextPosition === animatedClosedPosition.value) {
        isAnimatedOnMount.value = true;
        animatedCurrentIndex.value = _providedIndex;
        return;
      }

      if (animateOnMount) {
        animateToPosition(nextPosition, ANIMATION_SOURCE.MOUNT);
      } else {
        animatedPosition.value = nextPosition;
      }
      isAnimatedOnMount.value = true;
    },
    [_providedIndex, animateOnMount],
  );

  useAnimatedReaction(
    () => ({
      snapPoints: animatedSnapPoints.value,
      containerHeight: animatedContainerHeight.value,
    }),
    (result, _previousResult) => {
      const { snapPoints, containerHeight } = result;
      const _previousSnapPoints = _previousResult?.snapPoints;
      const _previousContainerHeight = _previousResult?.containerHeight;

      let nextPosition;
      let animationConfig;
      let animationSource = ANIMATION_SOURCE.SNAP_POINT_CHANGE;

      // 当弹窗正在关闭并且容器高度发生变化时，重新启动关闭动画到新位置
      if (animatedAnimationState.value === ANIMATION_STATE.RUNNING && animatedNextPositionIndex.value === -1 && _previousContainerHeight !== containerHeight) {
        animationSource = ANIMATION_SOURCE.CONTAINER_RESIZE;
        animationConfig = {
          duration: 0,
        };
        animateToPosition(containerHeight, animationSource, 0, animationConfig);
      }

      if (JSON.stringify(snapPoints) === JSON.stringify(_previousSnapPoints) || !isLayoutCalculated.value || !isAnimatedOnMount.value || containerHeight <= 0) {
        return;
      }

      runOnJS(print)({
        component: AdaptiveBottomSheet.name,
        method: 'useAnimatedReaction::OnSnapPointChange',
        params: {
          snapPoints,
        },
      });

      // 如果 snap points 改变时，停止动画并动画到更新的位置
      if (animatedAnimationState.value === ANIMATION_STATE.RUNNING && animatedNextPositionIndex.value !== animatedCurrentIndex.value) {
        nextPosition = animatedNextPositionIndex.value !== -1 ? snapPoints[animatedNextPositionIndex.value] : animatedNextPosition.value;
      } else if (animatedCurrentIndex.value === -1) {
        nextPosition = animatedClosedPosition.value;
      } else if (isInTemporaryPosition.value) {
        nextPosition = getNextPosition();
      } else {
        nextPosition = snapPoints[animatedCurrentIndex.value];

        // 如果容器高度发生变化，则跳过 snap 动画
        if (containerHeight !== _previousContainerHeight) {
          animationSource = ANIMATION_SOURCE.CONTAINER_RESIZE;
          animationConfig = {
            duration: 0,
          };
        }
      }
      animateToPosition(nextPosition, animationSource, 0, animationConfig);
    },
  );

  // 设置动画位置
  useAnimatedReaction(
    () => animatedPosition.value,
    _animatedPosition => {
      if (_providedAnimatedPosition) {
        _providedAnimatedPosition.value = _animatedPosition;
      }
    },
  );

  // 设置提供动画索引
  useAnimatedReaction(
    () => animatedIndex.value,
    _animatedIndex => {
      if (_providedAnimatedIndex) {
        _providedAnimatedIndex.value = _animatedIndex;
      }
    },
  );

  // 监听内部变量以检测捕捉点位置的变化
  useAnimatedReaction(
    () => ({
      _animatedIndex: animatedIndex.value,
      _animatedPosition: animatedPosition.value,
      _animationState: animatedAnimationState.value,
      _contentGestureState: animatedContentGestureState.value,
      _handleGestureState: animatedHandleGestureState.value,
    }),
    ({ _animatedIndex, _animationState, _contentGestureState, _handleGestureState }) => {
      const hasNoActiveGesture =
        (_contentGestureState === State.END || _contentGestureState === State.UNDETERMINED || _contentGestureState === State.CANCELLED) &&
        (_handleGestureState === State.END || _handleGestureState === State.UNDETERMINED || _handleGestureState === State.CANCELLED);

      if (_animationState !== ANIMATION_STATE.STOPPED || _animatedIndex % 1 !== 0 || !hasNoActiveGesture) {
        return;
      }

      // 索引变化时触发回调
      if (_animatedIndex !== animatedCurrentIndex.value) {
        runOnJS(print)({
          component: AdaptiveBottomSheet.name,
          method: 'useAnimatedReaction::OnStateChange',
          params: {
            animatedCurrentIndex: animatedCurrentIndex.value,
            animatedIndex: _animatedIndex,
          },
        });

        animatedCurrentIndex.value = _animatedIndex;
        runOnJS(handleOnStateChange)(_animatedIndex);
      }
    },
    [handleOnStateChange],
  );

      // 索引为 -1 时触发关闭回调
  useAnimatedReaction(
    () => animatedPosition.value,
    (_position, previousPosition) => {
      'worklet';
      // 只在以下情况触发回调：
      // 1. 位置确实发生了变化
      // 2. 提供了回调函数
      // 3. 位置变化超过 20px（避免频繁触发）
      if (_providedOnPositionChange && previousPosition !== undefined && previousPosition !== null && Math.abs(_position - previousPosition) > 20) {
        const containerHeight = animatedContainerHeight.value;
        const containerWidth = WINDOW_WIDTH;
        const visibleHeight = Math.max(0, containerHeight - _position);
        const visibleWidth = containerWidth;

        runOnJS(_providedOnPositionChange)({
          position: _position,
          visibleHeight,
          visibleWidth,
        });
      }
    },
    [_providedOnPositionChange, animatedContainerHeight],
  );

  // 监听索引变化并触发回调
  useEffect(() => {
    if (isAnimatedOnMount.value) {
      handleSnapToIndex(_providedIndex);
    }
  }, [_providedIndex, animatedCurrentIndex, isAnimatedOnMount, handleSnapToIndex]);

  // 头部左按钮回调
  const handleHeaderLeftPressInternal = useCallback(() => {
    if (onHeaderLeftPress) {
      onHeaderLeftPress();
    } else {
      handleClose();
    }
  }, [onHeaderLeftPress, handleClose]);

  print({
    component: AdaptiveBottomSheet.name,
    method: 'render',
    params: {
      animatedSnapPoints: animatedSnapPoints.value,
      animatedCurrentIndex: animatedCurrentIndex.value,
      providedIndex: _providedIndex,
    },
  });
  // 动态断点
  return (
    <AdaptiveSheetProvider value={externalContextVariables}>
      <AdaptiveSheetInternalProvider value={internalContextVariables}>
        <AdaptiveSheetGestureHandlersProvider gestureEventsHandlersHook={gestureEventsHandlersHook}>
          {/* 背景遮罩容器 */}
          <AdaptiveSheetBackdropContainer
            key="AdaptiveSheetBackdropContainer"
            animatedIndex={animatedIndex}
            animatedPosition={animatedPosition}
            backdropComponent={backdropComponent}
          />
          {/* 主容器*/}
          <AdaptiveSheetContainer
            key="AdaptiveSheetContainer"
            shouldCalculateHeight={!$modal}
            containerHeight={_animatedContainerHeight}
            containerOffset={animatedContainerOffset}
            topInset={topInset}
            bottomInset={bottomInset}
            detached={detached}
            style={_providedContainerStyle}>
            <Animated.View style={containerStyle}>
              {/* 背景容器 */}
              <AdaptiveSheetBackgroundContainer
                key="AdaptiveSheetBackgroundContainer"
                animatedIndex={animatedIndex}
                animatedPosition={animatedPosition}
                backgroundComponent={backgroundComponent}
                backgroundStyle={_providedBackgroundStyle}
              />
              {/* 内容遮罩容器 */}
              <Animated.View
                pointerEvents="box-none" // 允许点击穿透
                style={contentMaskContainerStyle}>
                {/* 可拖拽内容视图 */}
                <AdaptiveSheetDraggableView key="AdaptiveSheetDraggableView" style={contentContainerStyle}>
                  {/* 渲染内容：函数组件或直接内容 */}
                  {typeof Content === 'function' ? <Content /> : Content}
                  {/* 底部组件 */}
                  {footerComponent && <AdaptiveSheetFooterContainer footerComponent={footerComponent} />}
                </AdaptiveSheetDraggableView>
              </Animated.View>
              {/* 拖拽句柄容器或固定头部 */}
              {headerMode === 'fixed' ? (
                CustomHeaderComponent ? (
                  <CustomHeaderComponent
                    key="CustomHeaderComponent"
                    title={headerTitle}
                    height={headerHeight}
                    topInset={topInset}
                    leftButton={headerLeftButton}
                    rightButton={headerRightButton}
                    onLeftPress={handleHeaderLeftPressInternal}
                    onRightPress={onHeaderRightPress}
                    titleStyle={headerTitleStyle}
                    containerStyle={headerContainerStyle}
                    {...(headerCloseButtonColor !== undefined && { closeButtonColor: headerCloseButtonColor })}
                    sheetType="bottom"
                  />
                ) : (
                  <AdaptiveSheetFixedHeader
                    key="AdaptiveSheetFixedHeader"
                    title={headerTitle}
                    height={headerHeight}
                    topInset={topInset}
                    leftButton={headerLeftButton}
                    rightButton={headerRightButton}
                    onLeftPress={handleHeaderLeftPressInternal}
                    onRightPress={onHeaderRightPress}
                    titleStyle={headerTitleStyle}
                    containerStyle={headerContainerStyle}
                    {...(headerCloseButtonColor !== undefined && { closeButtonColor: headerCloseButtonColor })}
                  />
                )
              ) : (
                <AdaptiveSheetHandleContainer
                  key="AdaptiveSheetHandleContainer"
                  animatedIndex={animatedIndex}
                  animatedPosition={animatedPosition}
                  handleHeight={animatedHandleHeight}
                  enableHandlePanningGesture={enableHandlePanningGesture}
                  enableOverDrag={enableOverDrag}
                  enablePanDownToClose={enablePanDownToClose}
                  overDragResistanceFactor={overDragResistanceFactor}
                  handleComponent={handleComponent}
                  handleStyle={_providedHandleStyle}
                  handleIndicatorStyle={_providedHandleIndicatorStyle}
                />
              )}
            </Animated.View>
          </AdaptiveSheetContainer>
        </AdaptiveSheetGestureHandlersProvider>
      </AdaptiveSheetInternalProvider>
    </AdaptiveSheetProvider>
  );
});
const AdaptiveBottomSheet = memo(AdaptiveBottomSheetComponent);
AdaptiveBottomSheet.displayName = 'AdaptiveBottomSheet';

export default AdaptiveBottomSheet;
